package dcl.software.filesync.server.transfer;

import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class TransferUtil {

	private static final int SALT_SIZE = 256;
	private static byte[] salt = null;
	private static final Object syncObj = new Object();

	public static String symetricEncrypt2(final String message) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
	        IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeySpecException {
		SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
		if (salt == null) {
			synchronized (syncObj) {
				if (salt == null) {
					SecureRandom sr = new SecureRandom();
					salt = sr.generateSeed(456);
				}
			}
		}
		char[] password = "passworddddddddddddddddddddddddd".toCharArray();
		KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
		SecretKey tmp = factory.generateSecret(spec);
		SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
		System.out.println(tmp.getEncoded().length);
		/* Encrypt the message. */
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.ENCRYPT_MODE, secret);
		AlgorithmParameters params = cipher.getParameters();
		byte[] ciphertext = cipher.doFinal(message.getBytes("UTF-8"));
		return encode(ciphertext);
	}

	public static String symetricDecrypt2(final String encrypetedMessage) throws NoSuchAlgorithmException, NoSuchPaddingException,
	        InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeySpecException {
		char[] password = "passworddddddddddddddddddddddddd".toCharArray();

		Cipher cipher = Cipher.getInstance("AES");
		PBEKeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
		SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
		SecretKey tmp = factory.generateSecret(spec);
		SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
		cipher.init(Cipher.DECRYPT_MODE, secret);
		String plaintext = new String(cipher.doFinal(decode(encrypetedMessage)), "UTF-8");
		return plaintext;
	}

	public static String symetricEncrypt1(final String message) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
	        IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		String encryptionKey = "somethinggsometh";

		Cipher cipherInstance = Cipher.getInstance("AES");
		byte[] bytesOfKey = encryptionKey.getBytes();
		SecretKeySpec secretKeySpec = new SecretKeySpec(bytesOfKey, "AES");
		cipherInstance.init(Cipher.ENCRYPT_MODE, secretKeySpec);

		byte[] encryptedValue = cipherInstance.doFinal(message.getBytes("UTF-8"));
		String encryptedString = encode(encryptedValue);

		return encryptedString;
	}

	public static String symetricDecrypt1(final String encrypetedMessage) throws NoSuchAlgorithmException, NoSuchPaddingException,
	        InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
		String encryptionKey = "somethinggsometh";
		byte[] decodeBase64 = decode(encrypetedMessage);
		Cipher cipherInstance = Cipher.getInstance("AES");
		byte[] bytesOfKey = encryptionKey.getBytes();
		SecretKeySpec secretKeySpec = new SecretKeySpec(bytesOfKey, "AES");
		cipherInstance.init(Cipher.DECRYPT_MODE, secretKeySpec);
		byte[] unencryptedValue = cipherInstance.doFinal(decodeBase64);
		String unencryptedString = new String(unencryptedValue);
		return unencryptedString;
	}

	public String asymetricEncrypt(String message, Key key) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, key);
		return encode(cipher.doFinal(message.getBytes()));
	}

	public String asymetricDecrypt(String encrypted, Key key) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, key);
		return new String(cipher.doFinal(decode(encrypted)));
	}

	public String getEncodedHashWork(String toHash) throws NoSuchAlgorithmException {
		MessageDigest digest;
		digest = MessageDigest.getInstance("SHA-512");

		byte[] hashed = digest.digest(toHash.getBytes());

		return encode(hashed);
	}

	public static byte[] getSalt() {
		SecureRandom sr = new SecureRandom();
		return sr.generateSeed(SALT_SIZE);
	}

	public static String getEncodedHash(String toHash, byte[] salt) {
		if (salt.length != SALT_SIZE || toHash == null || toHash.length() < 8)
			throw new IllegalArgumentException("Password needs to have a length > 5 and salt a length of 256");
		int iterations = 40000;
		int hashLength = 512;
		String pepper = "!@#$%^123456QW<>";
		char[] chars = (toHash + pepper).toCharArray();

		PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, hashLength * 8);
		SecretKeyFactory skf;
		try {
			skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
		byte[] hash = null;
		try {
			hash = skf.generateSecret(spec).getEncoded();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
			return null;
		}
		System.out.println(hash.length);
		return encode(hash);
	}

	public static String encode(byte[] string) {
		return Base64.encodeBase64String(string);
	}

	public static byte[] decode(String string) {
		return Base64.decodeBase64(string);
	}
}
